#include "AnalyImage.h"

AnalyImage::AnalyImage()
{
    drawImage.Create(10,10);
}

AnalyImage::~AnalyImage()
{

}

wxBitmap AnalyImage::GetDrawImage()
{
    return drawImage;
}

unsigned char* Img8To24(unsigned char* i, long size)
{
	unsigned char* res = (unsigned char*)malloc(size * 3);
	unsigned char* ptr1 = &res[0];
	for(long s=0;s<size;s++)
	{
		*ptr1 = i[s];
		ptr1++;
		*ptr1 = i[s];
		ptr1++;
		*ptr1 = i[s];
		ptr1++;
	}
	return res;
}

void AnalyImage::SetImage(unsigned char* _imageData,long _height,long _width)
{
    currentImage.SetData(Img8To24(_imageData,_height*_width),_width,_height,false);
    if(drawImage.GetHeight() < _height || drawImage.GetWidth() < _width)
        drawImage.Create(wxSize(_width,_height));  //重设大小
    displayRawImage=true;
    displayFilterImage=false;
    Draw();
}

void AnalyImage::Draw()
{
    wxMemoryDC drawDC;
    drawDC.SelectObject(drawImage);
    if(displayRawImage)
        drawDC.DrawBitmap(currentImage,0,0,false);
    if(displayFilterImage)
        drawDC.DrawBitmap(fliterResImage,0,0,false);
    if(displayPosInf)
        DrawPos(MarkPos,drawDC);
    if(displayHandleArea)
        DrawHandleArea(drawDC);
    if(displayPointLinks)
        DrawLinkPoints(drawDC);
}

void AnalyImage::SetHandleArea(long xx,long yy)
{
    HandleAreaX=xx;
    HandleAreaY=yy;
    displayHandleArea=true;
    Draw();
}

void AnalyImage::DrawHandleArea(wxMemoryDC& dc)
{
    wxPen pen;
    pen.SetWidth(2);
    pen.SetColour(0,255,0);
    dc.SetPen(pen);
    dc.DrawLine(0,0,HandleAreaX,0);
    dc.DrawLine(0,0,0,HandleAreaY);
    dc.DrawLine(HandleAreaX,0,HandleAreaX,HandleAreaY);
    dc.DrawLine(0,HandleAreaY,HandleAreaX,HandleAreaY);
}

unsigned char* ImgRGBtoGray(const unsigned char* RGBdata,int imageHeight,int imageWidth)
{
    unsigned char* res=new unsigned char[imageHeight*imageWidth];
    for(int i=0;i<imageHeight*imageWidth;i++)
    {
        //res[i]=(RGBdata[i*3]*19595+RGBdata[i*3+1]*38469+RGBdata[i*3+2]*7472)>>16;
        res[i]=RGBdata[i*3];
    }
    return res;
}

long AnalyImage::PixelValue(int pixelValue,int Threshold)
{
    if(pixelValue>=Threshold)
        return pixelValue;
    else
        return 0;
}

long AnalyImage::calSumValue(std::function<long(int,int)> func)
{
    long sum=0;
    for(int i=0;i<HandleAreaY;i++)
    {
        for(int j=0;j<HandleAreaX;j++)
        {
            sum+=func(i,j);
        }
    }
    return sum;
}

wxPoint AnalyImage::grayCenter(int Threshold)
{
    wxPoint cPoint;
    size_t imageSize=currentImage.GetHeight()*currentImage.GetWidth();
    unsigned char* imageData=ImgRGBtoGray(currentImage.GetData(),currentImage.GetHeight(),currentImage.GetWidth());
    unsigned char* cImageData=RouteImage(imageData,imageSize);
    ReversalColor(cImageData,currentImage.GetHeight()*currentImage.GetWidth());
    long divV=calSumValue([&](int x,int y){return PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);});
    if(divV<=0)
    {
        wxMessageBox(wxT("图像没有有效数据或数据为空"),wxT("处理错误"));
        delete [] imageData;
        delete [] cImageData;
        return MarkPos;
    }
    cPoint.y=calSumValue([&](int x,int y){return x*PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);}) / divV;
    cPoint.x=calSumValue([&](int x,int y){return y*PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);}) / divV;
    delete [] imageData;
    delete [] cImageData;
    return cPoint;
}

wxPoint AnalyImage::GetGrayCenter(unsigned char* _imageData,int Threshold)
{
    wxPoint cPoint;
    size_t imageSize=currentImage.GetHeight()*currentImage.GetWidth();
    unsigned char* cImageData=RouteImage(_imageData,imageSize);
    ReversalColor(cImageData,imageSize);
    long divV=calSumValue([&](int x,int y){return PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);});
    if(divV<=0)
    {
        delete [] cImageData;
        throw (int)1;
    }
    cPoint.y=calSumValue([&](int x,int y){return x*PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);}) / divV;
    cPoint.x=calSumValue([&](int x,int y){return y*PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);}) / divV;
    delete [] cImageData;
    return cPoint;
}

void AnalyImage::DrawPos(wxPoint pos,wxMemoryDC& dc)
{
    wxPen pen;
    pen.SetColour(255,0,0);
    pen.SetWidth(3);
    dc.SetPen(pen);
    dc.DrawLine(pos.x-5,pos.y,pos.x+5,pos.y);
    dc.DrawLine(pos.x,pos.y-5,pos.x,pos.y+5);
}

void AnalyImage::HandleImage(int Threshold)
{
    displayPosInf=true;
    displayPointLinks=false;
    MarkPos=grayCenter(Threshold);
    Draw();
}

void AnalyImage::ReversalColor(unsigned char* imageData,size_t size)
{
    for(int i=0;i<size;i++)
    {
        imageData[i]=0xFF-imageData[i];
    }
}

unsigned char* AnalyImage::RouteImage(unsigned char* imageData,size_t size)
{
    unsigned char* resData=new unsigned char[size];
    long resPtr=0;
    for(int i=0;i<currentImage.GetHeight();i++)
    {
        for(int j=0;j<currentImage.GetWidth();j++)
        {
            resData[resPtr]=imageData[j*currentImage.GetHeight()+i];
            resPtr++;
        }
    }
    return resData;
}

void AnalyImage::FilterImage(int Threshold)
{
    displayFilterImage=true;
    displayRawImage=false;
    displayPointLinks=false;
    const unsigned char* raw=currentImage.GetData();
    size_t imageSize=currentImage.GetHeight()*currentImage.GetWidth()*3;
    unsigned char* res=(unsigned char*)malloc(imageSize);
    std::memcpy(res,raw,imageSize);
    ReversalColor(res,imageSize);
    for(int i=0;i<imageSize;i++)
    {
        res[i]=PixelValue(res[i],Threshold);
    }
    fliterResImage.SetData(res,currentImage.GetWidth(),currentImage.GetHeight(),false);
    Draw();
}

wxPoint AnalyImage::GetTargetPos()
{
    return MarkPos;
}

void AnalyImage::LinkPoints(wxPointList& pList)
{
    pointList=pList;
    displayPointLinks=true;
    Draw();
}

void AnalyImage::DrawLinkPoints(wxMemoryDC& dc)
{
    wxPen pen;
    pen.SetColour(0,0,255);
    pen.SetWidth(2);
    dc.SetPen(pen);
    for(const wxPoint* pos : pointList)
    {
        dc.DrawLine(pos->x-5,pos->y,pos->x+5,pos->y);
        dc.DrawLine(pos->x,pos->y-5,pos->x,pos->y+5);
    }
    //dc.DrawSpline(&pointList);
}